/**
 * 备份服务
 * 处理数据备份和恢复相关的业务逻辑
 */
import { dbService, TABLES } from './database'
import { taskService } from './task-service'
import type { Task } from './task-service'

/**
 * 备份数据类型
 */
export interface BackupData {
  version: number
  timestamp: string
  tasks: Task[]
  financialRecords: any[]
  pomodoros: any[]
  notes: any[]
}

/**
 * 备份服务类
 */
class BackupService {
  // 当前备份版本号
  private readonly VERSION = 1

  /**
   * 创建数据备份
   * @returns 备份数据对象
   */
  async createBackup(): Promise<BackupData> {
    try {
      // 获取所有表的数据
      const tasks = await taskService.getAllTasks()
      const financialRecords = await dbService.query(`SELECT * FROM ${TABLES.FINANCIAL_RECORDS}`)
      const pomodoros = await dbService.query(`SELECT * FROM ${TABLES.POMODOROS}`)
      const notes = await dbService.query(`SELECT * FROM ${TABLES.NOTES}`)
      
      // 创建备份对象
      const backup: BackupData = {
        version: this.VERSION,
        timestamp: new Date().toISOString(),
        tasks,
        financialRecords,
        pomodoros,
        notes
      }
      
      return backup
    } catch (error) {
      console.error('创建备份失败:', error)
      throw new Error('创建备份失败')
    }
  }
  
  /**
   * 将备份数据导出为JSON字符串
   * @returns JSON字符串
   */
  async exportBackupAsJson(): Promise<string> {
    try {
      const backup = await this.createBackup()
      return JSON.stringify(backup)
    } catch (error) {
      console.error('导出备份失败:', error)
      throw new Error('导出备份失败')
    }
  }
  
  /**
   * 将备份保存到文件系统
   * 仅在APP环境可用
   * @returns 保存的文件路径
   */
  async saveBackupToFile(): Promise<string> {
    // #ifdef APP-PLUS
    try {
      // 创建备份数据
      const backup = await this.createBackup()
      const jsonData = JSON.stringify(backup)
      
      // 生成文件名
      const date = new Date()
      const dateString = this.formatDate(date)
      const fileName = `backup_${dateString}.json`
      
      // 指定保存路径(App沙盒目录下的Documents)
      const savePath = plus.io.convertLocalFileSystemURL('_doc/backups/')
      
      // 确保目录存在
      await this.ensureDirectoryExists('_doc/backups/')
      
      // 保存文件
      const filePath = `${savePath}${fileName}`
      await this.writeFile(filePath, jsonData)
      
      return filePath
    } catch (error) {
      console.error('保存备份文件失败:', error)
      throw new Error('保存备份文件失败')
    }
    // #endif
  }
  
  /**
   * 从JSON字符串恢复数据
   * @param jsonString JSON字符串
   */
  async restoreFromJson(jsonString: string): Promise<void> {
    try {
      // 解析备份数据
      const backup = JSON.parse(jsonString) as BackupData
      
      // 验证备份格式
      if (!backup || !backup.version || !backup.timestamp) {
        throw new Error('无效的备份数据格式')
      }
      
      // 清空所有现有数据
      await dbService.executeSQL(`DELETE FROM ${TABLES.TASKS}`)
      await dbService.executeSQL(`DELETE FROM ${TABLES.FINANCIAL_RECORDS}`)
      await dbService.executeSQL(`DELETE FROM ${TABLES.POMODOROS}`)
      await dbService.executeSQL(`DELETE FROM ${TABLES.NOTES}`)
      
      // 恢复任务数据
      if (backup.tasks && Array.isArray(backup.tasks)) {
        for (const task of backup.tasks) {
          await taskService.saveTask(task)
        }
      }
      
      // 恢复财务记录
      if (backup.financialRecords && Array.isArray(backup.financialRecords)) {
        for (const record of backup.financialRecords) {
          await dbService.insert(TABLES.FINANCIAL_RECORDS, record)
        }
      }
      
      // 恢复番茄钟记录
      if (backup.pomodoros && Array.isArray(backup.pomodoros)) {
        for (const record of backup.pomodoros) {
          await dbService.insert(TABLES.POMODOROS, record)
        }
      }
      
      // 恢复笔记
      if (backup.notes && Array.isArray(backup.notes)) {
        for (const note of backup.notes) {
          await dbService.insert(TABLES.NOTES, note)
        }
      }
    } catch (error) {
      console.error('从JSON恢复失败:', error)
      throw new Error('恢复数据失败: ' + error.message)
    }
  }
  
  /**
   * 获取所有备份文件列表
   * 仅在APP环境可用
   * @returns 备份文件列表
   */
  async getBackupFiles(): Promise<{ name: string; date: string; path: string }[]> {
    // #ifdef APP-PLUS
    try {
      // 确保目录存在
      await this.ensureDirectoryExists('_doc/backups/')
      
      // 读取目录
      const backupDir = plus.io.convertLocalFileSystemURL('_doc/backups/')
      const fileList = await this.readDirectory(backupDir)
      
      // 筛选json文件并格式化结果
      const backupFiles = fileList
        .filter(fileName => fileName.endsWith('.json'))
        .map(fileName => {
          // 从文件名提取日期
          const dateMatch = fileName.match(/backup_(\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2})\.json/)
          const dateString = dateMatch ? dateMatch[1].replace(/_/g, ' ').replace(/-/g, ':') : '未知日期'
          
          return {
            name: fileName,
            date: dateString,
            path: `${backupDir}${fileName}`
          }
        })
        .sort((a, b) => b.date.localeCompare(a.date)) // 按日期降序排序
      
      return backupFiles
    } catch (error) {
      console.error('获取备份文件列表失败:', error)
      return []
    }
    // #endif
  }
  
  /**
   * 从文件恢复备份
   * 仅在APP环境可用
   * @param filePath 备份文件路径
   */
  async restoreFromFile(filePath: string): Promise<void> {
    // #ifdef APP-PLUS
    try {
      // 读取文件内容
      const jsonData = await this.readFile(filePath)
      
      // 从JSON恢复
      await this.restoreFromJson(jsonData)
    } catch (error) {
      console.error('从文件恢复失败:', error)
      throw new Error('从文件恢复失败: ' + error.message)
    }
    // #endif
    
    // #ifndef APP-PLUS
    throw new Error('此功能仅在App环境下可用')
    // #endif
  }
  
  /**
   * 确保目录存在
   * @param dirPath 目录路径
   */
  private async ensureDirectoryExists(dirPath: string): Promise<void> {
    // #ifdef APP-PLUS
    return new Promise((resolve, reject) => {
      plus.io.resolveLocalFileSystemURL(dirPath, () => {
        // 目录已存在
        resolve()
      }, () => {
        // 目录不存在，创建它
        plus.io.resolveLocalFileSystemURL('_doc/', (entry: any) => {
          entry.getDirectory('backups', { create: true }, () => {
            resolve()
          }, (error: any) => {
            reject('创建目录失败: ' + JSON.stringify(error))
          })
        }, (error: any) => {
          reject('获取文档目录失败: ' + JSON.stringify(error))
        })
      })
    })
    // #endif
  }
  
  /**
   * 读取目录内容
   * @param dirPath 目录路径
   * @returns 文件名列表
   */
  private async readDirectory(dirPath: string): Promise<string[]> {
    // #ifdef APP-PLUS
    return new Promise((resolve, reject) => {
      plus.io.resolveLocalFileSystemURL(dirPath, (entry: any) => {
        const reader = entry.createReader()
        reader.readEntries((entries: any[]) => {
          // 只获取文件名
          const fileNames = entries
            .filter(entry => entry.isFile)
            .map(entry => entry.name)
          resolve(fileNames)
        }, (error: any) => {
          reject('读取目录失败: ' + JSON.stringify(error))
        })
      }, (error: any) => {
        reject('获取目录失败: ' + JSON.stringify(error))
      })
    })
    // #endif
  }
  
  /**
   * 写入文件
   * @param filePath 文件路径
   * @param content 文件内容
   */
  private async writeFile(filePath: string, content: string): Promise<void> {
    // #ifdef APP-PLUS
    return new Promise((resolve, reject) => {
      plus.io.resolveLocalFileSystemURL(filePath, (entry: any) => {
        // 文件存在，先删除
        entry.remove(() => {
          this.createAndWriteFile(filePath, content, resolve, reject)
        }, (error: any) => {
          reject('删除已存在文件失败: ' + JSON.stringify(error))
        })
      }, () => {
        // 文件不存在，直接创建
        this.createAndWriteFile(filePath, content, resolve, reject)
      })
    })
    // #endif
  }
  
  /**
   * 创建并写入文件
   * 内部方法，用于writeFile
   */
  private createAndWriteFile(filePath: string, content: string, resolve: () => void, reject: (reason: string) => void): void {
    // #ifdef APP-PLUS
    const parentPath = filePath.substring(0, filePath.lastIndexOf('/') + 1)
    const fileName = filePath.substring(filePath.lastIndexOf('/') + 1)
    
    plus.io.resolveLocalFileSystemURL(parentPath, (entry: any) => {
      entry.getFile(fileName, { create: true }, (fileEntry: any) => {
        fileEntry.createWriter((writer: any) => {
          writer.onwrite = function() {
            resolve()
          }
          writer.onerror = function(error: any) {
            reject('写入文件失败: ' + JSON.stringify(error))
          }
          writer.write(content)
        }, (error: any) => {
          reject('创建写入器失败: ' + JSON.stringify(error))
        })
      }, (error: any) => {
        reject('创建文件失败: ' + JSON.stringify(error))
      })
    }, (error: any) => {
      reject('获取父目录失败: ' + JSON.stringify(error))
    })
    // #endif
  }
  
  /**
   * 读取文件内容
   * @param filePath 文件路径
   * @returns 文件内容
   */
  private async readFile(filePath: string): Promise<string> {
    // #ifdef APP-PLUS
    return new Promise((resolve, reject) => {
      plus.io.resolveLocalFileSystemURL(filePath, (entry: any) => {
        entry.file((file: any) => {
          const reader = new plus.io.FileReader()
          reader.onloadend = function() {
            resolve(this.result as string)
          }
          reader.onerror = function(error: any) {
            reject('读取文件失败: ' + JSON.stringify(error))
          }
          reader.readAsText(file)
        }, (error: any) => {
          reject('获取文件对象失败: ' + JSON.stringify(error))
        })
      }, (error: any) => {
        reject('获取文件失败: ' + JSON.stringify(error))
      })
    })
    // #endif
  }
  
  /**
   * 格式化日期为适合文件名的字符串
   * @param date 日期对象
   * @returns 格式化后的字符串
   */
  private formatDate(date: Date): string {
    const year = date.getFullYear()
    const month = String(date.getMonth() + 1).padStart(2, '0')
    const day = String(date.getDate()).padStart(2, '0')
    const hours = String(date.getHours()).padStart(2, '0')
    const minutes = String(date.getMinutes()).padStart(2, '0')
    const seconds = String(date.getSeconds()).padStart(2, '0')
    
    return `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`
  }
}

// 导出备份服务单例
export const backupService = new BackupService() 